//****************************************************************************************
//
// Module file for conversion routines between managed and unmanaged code
//
//****************************************************************************************

#include "Stdafx.h"

#include "Conversion.h"

using namespace System::Runtime::InteropServices;

namespace CheckersBoardEngine {

	 // Move Computing Model Conversion
	////////////////////////////////////////////////////////////////////

	// color conversion
	int ConvertColor(eColor clr)
	{
		return clr == eColor::White ? WHITE : BLACK;
	}

	// figure conversion
	int ConvertFigure(eFigure figure)
	{
		switch(figure)
		{
		case eFigure::WhiteMan:
			return WHITE | MAN;
		case eFigure::BlackMan:
			return BLACK | MAN;
		case eFigure::WhiteKing:
			return WHITE | KING;
		case eFigure::BlackKing:
			return BLACK | KING;
		default:
			return FREE;
		}
	}

	// figure conversion
	eFigure ConvertFigure(int figure)
	{
		switch(figure)
		{
		case WHITE | MAN:
			return eFigure::WhiteMan;
		case BLACK | MAN:
			return eFigure::BlackMan;
		case WHITE | KING:
			return eFigure::WhiteKing;
		case BLACK | KING:
			return eFigure::BlackKing;
		default:
			return eFigure::Nothing;
		}
	}


	// cleans up game rec
	void CleanUpGameRec(CBThreadParams* pParams) 
	{
		if(pParams->pBoard != NULL)
		{
			delete[] pParams->pBoard;
			pParams->pBoard = NULL;
		}

		pParams->color = 0;
		pParams->maxtime = 0;

		if(pParams->move != NULL)
		{
			delete pParams->move;
			pParams->move = NULL;
		}
	}
	
	// pre-calculation game situation conversion
	void ConvertGameRecord(CBThreadParams* pParams, CBGameRecord^ gameRec)
	{
		// clean up old information
		CleanUpGameRec(pParams);

		// setup board
		pParams->pBoard = new int[gameRec->Board->Length];
		for(int i = 0; i < gameRec->Board->Length; i++)
			pParams->pBoard[i] = ConvertFigure(gameRec->Board[i]);

		// other settings
		pParams->color = ConvertColor(gameRec->SideToMove);
		pParams->maxtime = gameRec->ComputingTime;

		// prepare new move
		pParams->move = new CBmove();
		memset(pParams->move, 0, sizeof(CBmove));
	}

	// converts coordinates
	Coordinates^ ConvertCoor(coor* c) 
	{
		Coordinates^ cOut = gcnew Coordinates();
		cOut->x = c->x;
		cOut->y = c->y;
		return cOut;
	}

	// converts computed move
	ComputedMove^ ConvertMove(CBmove* m)
	{
		ComputedMove^ mOut = gcnew ComputedMove();

		mOut->jumps = m->jumps;
		mOut->oldPiece = ConvertFigure(m->oldpiece);
		mOut->newPiece = ConvertFigure(m->newpiece);
		mOut->from = ConvertCoor(&m->from);
		mOut->to = ConvertCoor(&m->to);

		const int pathLen = 12;
		mOut->path = gcnew array<Coordinates^>(pathLen);
		mOut->del = gcnew array<Coordinates^>(pathLen);
		mOut->delpieces = gcnew array<eFigure>(pathLen);

		for(int i = 0; i < pathLen; i++) 
		{
			mOut->path[i] = ConvertCoor(&m->path[i]);
			mOut->del[i] = ConvertCoor(&m->del[i]);
			mOut->delpieces[i] = ConvertFigure(m->delpiece[i]);
		}

		return mOut;
	}

	 // Engine Options Model Conversion
	////////////////////////////////////////////////////////////////////////

	EngineOptions^ ConvertEngineOptions(ENGINE_OPTIONS *optIn)
	{
		EngineOptions^ optOut = gcnew EngineOptions();

		optOut->flags = optIn->flags;
		optOut->db_MB = optIn->db_MB;
		optOut->hash_MB = optIn->hash_MB;
		optOut->book = optIn->book;
		optOut->allscores = optIn->allscores;

		return optOut;
	}

	ENGINE_OPTIONS* ConvertEngineOptions(EngineOptions^ optIn)
	{
		ENGINE_OPTIONS* optOut = new ENGINE_OPTIONS();

		optOut->flags = optIn->flags;
		optOut->db_MB = optIn->db_MB;
		optOut->hash_MB = optIn->hash_MB;
		optOut->book = optIn->book;
		optOut->allscores = optIn->allscores;

		return optOut;
	}

	EngineMoreOptions^ ConvertEngineOptions(MORE_ENGINE_OPTIONS *optIn)
	{
		EngineMoreOptions^ optOut = gcnew EngineMoreOptions();

		optOut->flags = optIn->flags;
		optOut->max_dbpieces = optIn->max_dbpieces;
		optOut->wld_egdb_enable = optIn->wld_egdb_enable;
		if(optIn->wld_directory != NULL) 
		{
			optOut->wld_directory = gcnew String(optIn->wld_directory);
		}
		optOut->mtc_egdb_enable = optIn->mtc_egdb_enable;
		if(optIn->mtc_directory != NULL)
		{
			optOut->mtc_directory = gcnew String(optIn->mtc_directory);
		}
		if(optIn->book_filename != NULL)
		{
			optOut->book_filename = gcnew String(optIn->book_filename);
		}
		optOut->search_threads = optIn->search_threads;

		return optOut;
	}

	void StringToChar(char* szOutput, String^ s, int len) 
	{
		char* str2 = (char*)Marshal::StringToHGlobalAnsi(s).ToPointer();
		strcpy_s(szOutput, len, str2);
		Marshal::FreeHGlobal((IntPtr)str2);
	}

	MORE_ENGINE_OPTIONS* ConvertEngineOptions(EngineMoreOptions^ optIn)
	{
		MORE_ENGINE_OPTIONS* optOut = new MORE_ENGINE_OPTIONS();

		optOut->flags = optIn->flags;
		optOut->max_dbpieces = optIn->max_dbpieces;
		optOut->wld_egdb_enable = optIn->wld_egdb_enable;
		if(optIn->wld_directory != nullptr) 		
		{
			StringToChar(optOut->wld_directory, optIn->wld_directory, 260);
		}
		optOut->mtc_egdb_enable = optIn->mtc_egdb_enable;
		if(optIn->mtc_directory != nullptr)
		{
			StringToChar(optOut->mtc_directory, optIn->mtc_directory, 260);
		}
		if(optIn->book_filename != nullptr)
		{
			StringToChar(optOut->book_filename, optIn->book_filename, 260);
		}
		optOut->search_threads = optIn->search_threads;

		return optOut;
	}





}


